Skip to content

CalderaForms 1.5.9.1 XSS (WordPress plugin) - tutorial

Notifications You must be signed in to change notification settings

mindpr00f/CVE-2018-7747

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 

Repository files navigation

CVE-2018-7747

CalderaForms 1.5.9.1 XSS (WordPress plugin) - tutorial


CalderaForm è un plugin per WordPress che permette di creare facilmente dei form tramite drag and drop. Durante una recente attività mi è capitato di testare alcuni portali, uno dei quali ospitava proprio un form di contatti creato tramite questo plugin. La configurazione personalizzata dell'istanza in oggetto mi ha permesso di trovarne una vulnerabilità: data la sua natura semplice, da manuale, credo che sia un buon pretesto per illustrare alcuni meccanismi a chi è alle prime armi.

Scopo esclusivamente didattico - non utilizzare queste informazioni per testare target senza esplicita autorizzazione né per scopi illeciti - non tuffarsi in acqua fredda durante la digestione - vestirsi a cipolla quando fa caldo

Per l'exploit completo:
https://www.exploit-db.com/exploits/44489/
Per la CVE:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-7747


CONFIGURAZIONE

Nella configurazione oggetto di analisi, il form era impostato per rispondere con un messaggio di ringraziamento rivolto all'utente, chiamandolo con il nome appena inserito.

Per replicare l'ambiente di test, installare in locale un'istanza di WordPress e installare il plugin CalderaForms versione 1.5.9.1 (disponibile qui o qui).

Una volta installato, dalla console amministrativa di WordPress > colonna di sinistra > "Caldera Forms" > top buttons > "New Form" > selezioniare Contact Form, rinominare e "Create Form"

alt text

Una volta creato è possibile modificarne la configurazione: top buttons > "Form Settings" > modificare il Success Message in modo che includa uno dei dati inseriti dall'utente. Click sul box e appare una tendina di suggerimenti.
Aggiungere %first_name%

alt text

Top buttons > "Save Form"

Per inserire il form in una pagina: colonna di sinistra > "Pages" > "Sample Page" > "Edit" > "Caldera Form" > selezionare il form appena creato > "Insert Form" > colonna di destra > "Update"

alt text

Done.


RICOGNIZIONE E INDIVIDUAZIONE VETTORE

Andiamo ad affrontare uno ad uno gli step necessari per costruire questo tipo di attacco, secondo il paradigma divide et impera.

In fase di test, quando si interagisce con un componente bisogna sempre prestare attenzione alle sue reazioni in base agli stimoli dati; in particolare, ci concentriamo sul "percorso" dei dati da noi inseriti e le eventuali trasformazioni che essi subiscono.

Un esempio specifico per il nostro caso è il seguente:

  1. Visitiamo la pagina contenente il form: http://127.0.0.1/wordpress/sample-page/

  2. Popoliamo il form con i seguenti dati
    "First Name": myName
    "Last Name": myLast
    "Email Address": my@e.mail
    "Comments": myComm

  3. I dati vengono elaborati secondo la logica del plugin

  4. Il messaggio di ringraziamento ricevuto contiene la stringa da noi inserita nel campo First Name
    "Thank you myName, form has been successfully submitted."

alt text

La stringa da noi inserita nel campo "First Name" ci viene restituita nel messaggio di ringraziamento.
In particolare, la stringa è contenuta in un div tag HTML.
Il nostro input finisce nell'HTML della pagina.
Considerazione: "Ci piace. Abbiamo un punto di contatto."

Facciamo un passo in avanti. Come viene trattato il nostro input durante la fase che abbiamo chiamato di "elaborazione" (punto 2)? In particolare, quello che vogliamo sapere è: abbiamo delle limitazioni sui caratteri (e le loro combinazioni) che possiamo usare? Ovviamente l'obiettivo è quello di riuscire a iniettare "roba". Quando si cerca di effettuare una injection bisogna tenere a mente dove finisce il nostro input e usare "la lingua" adeguata.

Il nostro input viene elaborato da un interprete SQL? Dobbiamo parlare la sua lingua
Il nostro input viene elaborato da uno script PHP? Dobbiamo parlare la sua lingua
Il nostro input finisce su una pagina HTML? ...

Quindi quello che ci interessa è capire se possiamo usare i caratteri e i costrutti tipici dell'HTML e in particolare, data la capacità di questo linguaggio di contenere/interpretare codice JavaScript, capire se troviamo una strategia per inserire il nostro codice nella "zona di atterraggio", ovvero il tag div notato prima.

Per fare questo inseriamo nel campo "First Name" un semplice tag HTML e vediamo se viene "sanitizzato" (da sanitized), ovvero se viene modificato in modo tale da essere reso innocuo/non interpretabile, oppure se ci viene restituito tale e quale. Usiamo a questo scopo un tag <br>, utilizzato per inserire un line break nel testo.

Seguendo la numerazione precedente:

  1. Popoliamo il form con i seguenti dati
    "First Name": m<br>yName
    "Last Name": myLast
    "Email Address": my@e.mail
    "Comments": myComm

  2. Il messaggio di ringraziamento contiene il nostro tag HTML, che non è stato modificato, ed esso viene correttamente interpretato, inserendo un line break nel mezzo del messaggio

"Thank you m  
yName, form has been successfully submitted."

alt text

Considerazione: "Ci piace. Possiamo usare i simboli minore-di e maggiore-di, possiamo inserire tag HTML che non vengono sanitizzati e vengono interpretati."

Passo avanti. Sostituiamo il tag di formattazione con qualcosa di più utile, come un tag <script>, che ci permette di inserire ed eseguire codice JavaScript all'interno della pagina.

  1. Popoliamo il form con i seguenti dati
    "First Name": m<script>alert(1);</script>yName
    "Last Name": myLast
    "Email Address": my@e.mail
    "Comments": myComm

  2. Il messaggio di ringraziamento contiene il nostro tag HTML, che non è stato modificato, e che viene correttamente interpretato, mostrandoci un box di alert

alt text

Considerazione 1: "Ci piace. Possiamo eseguire codice JavaScript arbitrario nel contesto del browser dell'utente."
Considerazione 2: "Non ci piace. L'utente che esegue il JavaScript siamo noi stessi"


STORE & RECALL

La situazione è questa: possiamo eseguire JavaScript tramite un sito non controllato da noi nel contesto del browser di un utente, ma questo utente, al momento, è lo stesso che inserisce i valori nel form. Tutto ciò è abbastanza inutile.
L'idea è questa: esiste un modo di richiamare il messaggio di ringraziamento contenente il nostro codice da eseguire?

Torniamo al nostro primo submit, quello di "perlustrazione" (o ri-eseguiamo i primi step).

Analizzando il traffico di rete o il sorgente della pagina, capiamo che il form esegue una richiesta POST verso l'indirizzo

http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4

(l'ultima parte può variare, modificarla opportunamente in tutti gli esempi che seguono)
ovvero verso l'indirizzo

http://<target>/cf-api/<form-id>

e che la risposta di questa richiesta è un JSON contenente alcuni dati, tra cui il messaggio di ringraziamento, e avente la seguente struttura:

{
      "data":
          {"cf_id":"48"},
      "html":"<div class=\" alert alert-success\">Thank you myName, form has been successfully submitted.<\/div>",
      "type":"complete",
      "form_id":"CF5ad9b3176c0f4",
      "form_name":"MyContactForm",
      "status":"complete"
}

teniamo da parte questa informazione, ci torneremo a breve; soprattutto notiamo i campi "form_id" e "cf_id".

Cosa c'è all'indirizzo verso il quale viene eseguita la POST? Senza troppe supposizioni, vediamo cosa accade se eseguiamo una GET, ovvero visitiamo la pagina all'indirizzo http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4 e troviamo, né più né meno, l'HTML del form in questione.

  1. Popoliamo il form con i seguenti dati
    "First Name": myRedirectedName
    "Last Name": myLast
    "Email Address": my@e.mail
    "Comments": myComm

e controlliamo il traffico di rete che deriva dal submit

alt text

Questa volta riceviamo un codice HTTP 302 (redirect) verso la location /wordpress/cf-api/CF5ad9b3176c0f4/?cf_su=1&cf_id=49 che ci restituisce, né più né meno, l'HTML contenente il tag div del messaggio di ringraziamento.

Notiamo il formato di questo indirizzo:

http://<target>/cf-api/<form-id>/?cf_su=1&cf_id=<cf-id>

dove i valori di <form-id> e <cf-id> sono proprio quelli contenuti nel JSON precedentemente analizzato, rispettivamente "form_id" e "cf_id".

Abbiamo risposto alla domanda di partenza? Si. Abbiamo trovato un modo per richiamare il contenuto del messaggio di ringraziamento.
Considerazione : "Ci piace. Possiamo richiamare, secondo necessità, il messaggio contenente i nostri dati."


BUILD IT UP

Tiriamo le fila, congiungendo tutte le informazioni che abbiamo raccolto fino ad ora e confezioniamo un attacco.
1) salviamo il nostro codice malevolo sul target
2) raccogliamo i dati necessari a recuperare tale codice
3) costruiamo la URL adatta a "innescare" (da "to trigger") il nostro attacco

  1. Popoliamo il form (da una delle due pagine, è indifferente) con i seguenti dati
    "First Name": m<script>document.body.innerHTML=String.fromCodePoint(128046);</script>yName
    "Last Name": myLast
    "Email Address": my@e.mail
    "Comments": myComm

  2. Tramite l'analisi del traffico generato, che sia leggere il JSON ricevuto nel caso della pagina sample-page o che sia leggere il redirect nel caso della pagina contenente solo il form, recuperiamo gli identificativi form_id e cf_id

{  
      "data":  
          {"cf_id":"69"},  
      "html":"...",  
      "type":"...",  
      "form_id":"CF5ad9b3176c0f4",  
      "form_name":"...",  
      "status":"..."  
}
  1. Costruiamo e utilizziamo la URL per eseguire il nostro attacco

http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4/?cf_su=1&cf_id=69

alt text


Alcune considerazioni:

  • Notare che il contenuto (o più in generale il comportamento) dell'ultima pagina visitata è controllato da noi; usare la fantasia
  • Riflettere sul fatto che la modifica della pagina effettuata tramite il nostro codice JavaScript avviene all'interno del browser dell'utente: l'XSS è un tipo di attacco definito client-side
  • Perché è stato necessario individuare un modo per richiamare lo script?
    Perchè l'idea dietro a un attacco di tipo XSS è quella di eseguire del codice nel contesto del browser della vittima; durante i primi test, abbiamo eseguito codice JS, ma in maniera volatile e nel contesto del nostro stesso browser.
  • Perché è stata usata una mucca? Perché è carina
  • Il parametro della richiesta GET "cf_id" è un identificativo (progressivo) del set di dati inseriti nel form; diminuendo quindi quel valore è possibile procedere "a ritroso nel tempo" e recuperare le informazioni precedentemente inviate da altri. Nel caso in cui Giove fosse nello Scorpione, Venere non fosse contro Saturno e il form fosse impostato per contenere nel messaggio di ringraziamento anche l'indirizzo email dell'utente, sarebbe ipoteticamente possibile recuperare gli indirizzi dei passati visitatori

Al lettore si propone, se interessato, di:

  • ripetere l'attacco e costruire un buffer opportuno affinché la vittima veda un alert contenente la stringa "MUCCA"
  • ripetere l'esercizio precendete senza utilizzare il carattere ' (apice, single quote), il carattere " (virgolette, double quotes) o il carattere ` (accento grave, backtick o backquote o grave accent), assente dal layout delle tastiere italiane
  • sviluppare uno script, nel linguaggio preferito, che, dato l'indirizzo della pagina sul proprio portale contenente il form, esegua le seguenti operazioni:
    • compilazione e invio del form
    • controllo di restituzione di qualcuno dei campi inseriti
    • costruzione e invio di un buffer malevolo all'interno del campo utile
    • restituzione dell'indirizzo della pagina con cui richiamare l'attacco
  • cambiare la configurazione fatta all'inizio del form (modificare il messaggio di ringraziamento) e ritestare lo script del punto precedente

About

CalderaForms 1.5.9.1 XSS (WordPress plugin) - tutorial

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published